; Unwanted - Uninstall Helper
; (c) 2012 by Dave Fulgham
; an AutoIt3 script - www.autoitscript.com
; To DO:
; - Feedback if INI populated uninstalls are not present on the system
;
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Res_Comment=Unwanted - Uninstall Helper
#AutoIt3Wrapper_Res_Description=Unwanted - Uninstall Helper
#AutoIt3Wrapper_Res_Fileversion=1.0.0.6
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_LegalCopyright=(c) 2012 Dave Fulgham
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=highestAvailable
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1)
Opt("MustDeclareVars", 1)
Dim $Form1, $gGroupFrame, $lblAllLabel, $lblUninstallLabel, $lvAllInstalled, $lvToUninstall, $bPushToBottom, $bPushToTop
Dim $bBumpFromUninstall, $bBumpToUninstall, $HideMS, $HideUpdates, $bUninstall, $FilterInput, $Filter, $bClear, $bApply
Dim $lastLviClicked, $lastLviClickTime, $bGotDoubleClick, $hLvAllInstalled, $hLvToUninstall, $aPointerOver
Enum $left, $right
Dim $aAllUninstStrings[1] = ["xxxx"]

#Region ### START Koda GUI section ### Form=c:\users\dave\desktop\script utils\uninstallhelper\unwantedsxs.kxf
$Form1 = GUICreate("Unwanted - Uninstall Helper", 981, 499, 198, 163)
$gGroupFrame = GUICtrlCreateGroup("", 0, 0, 454, 438)
$gGroupFrame = GUICtrlCreateGroup("", 524, 0, 454, 438)
$lblAllLabel = GUICtrlCreateLabel("All Installed Programs", 315, 0, 134, 20)
GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif")
$lblUninstallLabel = GUICtrlCreateLabel("Uninstall", 535, 0, 55, 20)
GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif")
$lvAllInstalled = GUICtrlCreateListView("Program|Publisher|Uninstall", 5, 20, 444, 410)
GUICtrlSetOnEvent($lvAllInstalled, "ListviewClick")
$lvToUninstall = GUICtrlCreateListView("Program|Publisher|Uninstall", 529, 20, 444, 410, $LVS_SHOWSELALWAYS)
GUICtrlSetOnEvent($lvToUninstall, "ListviewClick")
$bPushToTop = GUICtrlCreateButton("/\", 456, 128, 65, 33)
GUICtrlSetOnEvent($bPushToTop, "PushToTop")
GUICtrlSetState($bPushToTop, $GUI_DISABLE)
$bBumpToUninstall = GUICtrlCreateButton(">", 456, 176, 65, 33)
GUICtrlSetState($bBumpToUninstall, $GUI_DISABLE)
$HideMS = GUICtrlCreateCheckbox("Hide All Microsoft", 16, 440, 105, 17)
GUICtrlSetOnEvent($HideMS, "PopulateWithInstalled")
GUICtrlSetState($HideMS, $GUI_CHECKED)
$HideUpdates = GUICtrlCreateCheckbox("Hide Updates", 16, 462, 97, 17)
GUICtrlSetOnEvent($HideUpdates, "PopulateWithInstalled")
GUICtrlSetState($HideUpdates, $GUI_CHECKED)
$bBumpFromUninstall = GUICtrlCreateButton("<", 456, 224, 65, 33)
GUICtrlSetState($bBumpFromUninstall, $GUI_DISABLE)
$bPushToBottom = GUICtrlCreateButton("\/", 456, 272, 65, 33)
GUICtrlSetOnEvent($bPushToBottom, "PushToBottom")
GUICtrlSetState($bPushToBottom, $GUI_DISABLE)
$bUninstall = GUICtrlCreateButton("Uninstall", 848, 448, 105, 33)
GUICtrlSetOnEvent($bUninstall, "DoUninstallQueue")
$FilterInput = GUICtrlCreateInput("", 168, 463, 153, 20)
$Filter = GUICtrlCreateLabel("Filter:", 136, 465, 36, 20)
$bClear = GUICtrlCreateButton("X", 320, 463, 17, 20)
GUICtrlSetOnEvent($bClear, "ClearFilter")
$bApply = GUICtrlCreateButton("Apply", 336, 463, 49, 20)
GUICtrlSetOnEvent($bApply, "PopulateWithInstalled")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
Populate($lvAllInstalled)

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
$hLvAllInstalled = GUICtrlGetHandle($lvAllInstalled)
$hLvToUninstall = GUICtrlGetHandle($lvToUninstall)

While 1
	Sleep(100)
WEnd

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ;MsgBox(0, "Close Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle)
            Exit
    EndSelect
EndFunc   ;==>SpecialEvents

Func ListviewClick()
   ;MsgBox(0, "Debug", "Clicked:" & @GUI_CtrlId)
   ;ConsoleWrite("@GUI_CtrlHandle is: " & @GUI_WinHandle)
   $aPointerOver = GUIGetCursorInfo($Form1)
   If ($aPointerOver[4] = $lvAllInstalled) Then
	    SetButtons($left)
		;ConsoleWrite("Left side" & @CRLF)
	ElseIf ($aPointerOver[4] = $lvToUninstall) Then
	    SetButtons($right)
		;ConsoleWrite("Right side" & @CRLF)
   EndIf
EndFunc

Func Populate($ourList)
	Local $ourLvi
	;$ourLine = GUICtrlCreateListViewItem("Test|Rest", $lvAllInstalled)
	;GUICtrlSetOnEvent($ourLine, "ListviewClick")
	;$ourLine = GUICtrlCreateListViewItem("Best|Lest", $lvAllInstalled)
	;GUICtrlSetOnEvent($ourLine, "ListviewClick")
	;MsgBox(0, "Debug", $allUninstStrings)
	If FileExists(@ScriptDir & "\unwanted.ini") Then
		Local $savedUninstalls = IniReadSection(@ScriptDir & "\unwanted.ini", "Uninstall")
		If @error = 1  Then
			MsgBox(16, "Error", "Couldn't read INI file " & @ScriptDir & "\unwanted.ini")
			Return
		EndIf
		For $step = 1 To $savedUninstalls[0][0]
			Local $ourSavedEntry = $savedUninstalls[$step][1]
			;MsgBox(0, "Debug", "Step: " & $step & ", read: " & $ourSavedEntry & $allUninstStrings)
			Local $exploded = StringSplit($ourSavedEntry, "|", 2)
			_ArrayAdd($aAllUninstStrings, $exploded[2])
			$ourLvi = GUICtrlCreateListViewItem($ourSavedEntry, $lvToUninstall)
			GUICtrlSetOnEvent($ourLvi, "ListviewClick")
		Next
	EndIf
;	MsgBox(0, "Debug", $allUninstStrings)
	PopulateWithInstalled()
EndFunc

Func PopulateWithInstalled()
	Local $ourWalk, $ourCLSID, $friendlyName, $pubName, $uninstallString, $ourLine
	Local $noms = GUICtrlRead($HideMS)
	Local $noupdates = GUICtrlRead($HideUpdates)
	Local $filterBy = GUICtrlRead($FilterInput)
	;_GUICtrlListView_Scroll($ListView1, 0, -3500)
	_GUICtrlListView_BeginUpdate($lvAllInstalled)
	_GUICtrlListView_DeleteAllItems($lvAllInstalled)
	If StringInStr(@OSArch, "64") Then
		Local $scopes[2] = ["", "64"]
	Else
		Local $scopes[1] = [""]
	EndIf
	For $appendage In $scopes
		$ourWalk = 0
		While 1
			;MsgBox(0, "Debug", $appendage)
			$ourWalk = $ourWalk +1
			$ourCLSID = RegEnumKey("HKEY_LOCAL_MACHINE" & $appendage & "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", $ourWalk)
			If @error Then ExitLoop
			$friendlyName = RegRead("HKEY_LOCAL_MACHINE" & $appendage & "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $ourCLSID, "DisplayName")
			$pubName = RegRead("HKEY_LOCAL_MACHINE" & $appendage & "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $ourCLSID, "Publisher")
			; Bail if filter in force and no match
			If (StringLen($filterBy) > 0) Then
				;MsgBox(0, "Debug", "filterBy was > 0" & @CRLF & "FIleterby is: >" & $filterBy & "<")
				If Not (StringInStr($friendlyName, $filterBy, False) Or StringInStr($pubName, $filterBy, False)) Then ContinueLoop
			EndIf
			If ($noms = $GUI_CHECKED) And (StringInStr($pubName, "Microsoft Corporation") Or StringInStr($pubName, "Microsoft")) Then ContinueLoop
			If ($noupdates = $GUI_CHECKED) And (StringInStr($friendlyName, "(KB") Or StringInStr($friendlyName, "(SP")) Then ContinueLoop
			$uninstallString = RegRead("HKEY_LOCAL_MACHINE" & $appendage & "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $ourCLSID, "UninstallString")
			For $step = 1 To (UBound($aAllUninstStrings) - 1)
				;MsgBox(0, "Dubeg", $aAllUninstStrings[$step] & @CRLF & $uninstallString)
				If StringCompare($aAllUninstStrings[$step], $uninstallString) = 0 Then
					;MsgBox(0, "Dubeg", "Saw match with uninst string")
					ContinueLoop 2
				EndIf
			Next
			If $friendlyName Then
				$ourLine = GUICtrlCreateListViewItem($friendlyName & "|" & $pubName & "|" & $uninstallString, $lvAllInstalled)
				GUICtrlSetOnEvent($ourLine, "ListviewClick")
			EndIf
		WEnd
	Next

	Local $blah[3] = [0,0,0]
	_GUICtrlListView_SimpleSort($lvAllInstalled, $blah, 0)
	_GUICtrlListView_EndUpdate($lvAllInstalled)
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	Local $lvTarget, $lviBumped, $lviText, $uninstallString
	Local $renegeUninst = False
    Local $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	Local $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    If DllStructGetData($tNMHDR, "Code") = $NM_DBLCLK Then
		If ($hWndFrom = $hLvAllInstalled) Or ($hWndFrom = $hLvToUninstall) Then
			Local $aLV_Click_Info = _GUICtrlListView_SubItemHitTest($hWndFrom)
			; As long as the click was on an item or subitem
			If $aLV_Click_Info[0] <> -1 Then
				If $hWndFrom = $hLvAllInstalled Then
					$lvTarget = $lvToUninstall
				ElseIf $hWndFrom = $hLvToUninstall Then
					$lvTarget = $lvAllInstalled
					$renegeUninst = True
				EndIf
				$lviText = _GUICtrlListView_GetItemTextString($hWndFrom, $aLV_Click_Info[0])
				$lviBumped = GUICtrlCreateListViewItem($lviText, $lvTarget)
				GUICtrlSetOnEvent($lviBumped, "ListviewClick")
				_GUICtrlListView_DeleteItem($hWndFrom, $aLV_Click_Info[0])
				$uninstallString = StringSplit($lviText, "|", 2)
				If $renegeUninst = True Then
					; Sort all installs
					Local $blah[3] = [0,0,0]
					_GUICtrlListView_BeginUpdate($lvAllInstalled)
					_GUICtrlListView_SimpleSort($lvAllInstalled, $blah, 0)
					_GUICtrlListView_EndUpdate($lvAllInstalled)
					For $step = 1 To (UBound($aAllUninstStrings) - 1)
						;MsgBox(0, "Dubeg", $aAllUninstStrings[$step] & @CRLF & $uninstallString[2])
						If StringCompare($aAllUninstStrings[$step], $uninstallString[2]) = 0 Then
							;MsgBox(0, "Dubeg", "Saw match with uninst string")
							$aAllUninstStrings[$step] = "xxx"
						EndIf
					Next
					;MsgBox(0, "Debug", $allUninstStrings)
					;$allUninstStrings = StringReplace($allUninstStrings, $uninstallString, "")
					;MsgBox(0, "Debug", $allUninstStrings)
				Else
					_ArrayAdd($aAllUninstStrings, $uninstallString[2])
				EndIf
			EndIf
		EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc

Func SetButtons($side)
	If ($side = $left) Then
		;GUICtrlSetState($bBumpFromUninstall, $GUI_DISABLE)
		;GUICtrlSetState($bBumpToUninstall, $GUI_ENABLE)
		GUICtrlSetState($bPushToBottom, $GUI_DISABLE)
		GUICtrlSetState($bPushToTop, $GUI_DISABLE)
	ElseIf ($side = $right) Then
		;GUICtrlSetState($bBumpFromUninstall, $GUI_ENABLE)
		;GUICtrlSetState($bBumpToUninstall, $GUI_DISABLE)
		GUICtrlSetState($bPushToBottom, $GUI_ENABLE)
		GUICtrlSetState($bPushToTop, $GUI_ENABLE)
	EndIf
EndFunc

Func PushToBottom()
	Local $ourIndex = _GUICtrlListView_GetSelectionMark($lvToUninstall)
	ConsoleWrite($ourIndex & @CRLF)
	If $ourIndex > -1 Then
		Local $lviText = _GUICtrlListView_GetItemTextString($lvToUninstall, $ourIndex)
		Local $lviBumped = GUICtrlCreateListViewItem($lviText, $lvToUninstall)
		;GUICtrlSetOnEvent($lviBumped, "ListviewClick")
		_GUICtrlListView_DeleteItem(GUICtrlGetHandle($lvToUninstall), $ourIndex)
	EndIf
EndFunc

Func PushToTop()
	Local $ourIndex = _GUICtrlListView_GetSelectionMark($lvToUninstall)
	ConsoleWrite($ourIndex & @CRLF)
	If $ourIndex > -1 Then
		Local $lviText = _GUICtrlListView_GetItemTextString($lvToUninstall, $ourIndex)
		_GUICtrlListView_DeleteItem(GUICtrlGetHandle($lvToUninstall), $ourIndex)
		Local $lviBumped = _GUICtrlListView_InsertItem($lvToUninstall, "", 0)
		_GUICtrllistview_UpdateItem($lvToUninstall, 0, $lviText)
		;GUICtrlSetOnEvent($lviBumped, "ListviewClick")
	EndIf
EndFunc

Func ClearFilter()
	GUICtrlSetData($FilterInput, "")
	PopulateWithInstalled()
EndFunc

Func _GUICtrllistview_UpdateItem($argListview, $argIndex, $argText)
	Local $ourText = StringSplit($argText, "|", 2)
	For $step = 0 To 2
		_GUICtrlListView_SetItem($argListview, $ourText[$step], $argIndex, $step)
	Next
EndFunc

Func DoUninstallQueue()
	Local $saveToINI = False
	Local $uninstallEntry, $uninstallSplit, $iniPath
	Local $ourUninstalls = _GUICtrlListView_GetItemCount(GUICtrlGetHandle($lvToUninstall))
	If ($ourUninstalls < 1) Then Return
	Local $ourChoice = MsgBox(35, "Uninstall", "Do you wish to save your choices for future uninstalls?")
	If $ourChoice = 2 Then
		Return
	ElseIf $ourChoice = 6 Then
		$saveToINI = True
		If (StringInStr(DriveGetType(StringLeft(@ScriptDir, 2)), "CDROM")) Then
			MsgBox(0, "Read-only", "Unwanted is being run from a read-only location, your selections will be saved to the file UNWANTED.INI on the Desktop. Please copy this file to your read-only media to keep your updated selctions.")
			$iniPath = @DesktopDir & "\unwanted.ini"
		Else
			$iniPath = @ScriptDir & "\unwanted.ini"
		EndIf
		IniDelete($iniPath, "Uninstall")
	EndIf
	For $step = 0 to ($ourUninstalls - 1)
		$uninstallEntry = _GUICtrlListView_GetItemTextString($lvToUninstall, $step)
		;MsgBox(0, "Debug", $uninstallEntry & @ScriptDir)
		If ($saveToINI = True) Then
			Local $ourResult = IniWrite($iniPath, "Uninstall", $step, $uninstallEntry)
			;MsgBox(0, "Debug", $ourResult)
		EndIf
		$uninstallSplit = StringSplit($uninstallEntry, "|", 2)
		Local $ourExit = RunWait($uninstallSplit[2])
		;MsgBox(0, "Debug", ">C >" & $uninstallSplit[2] & "<" & @CRLF & "ourExit: " & $ourExit & @CRLF & "error: " & @error & @CRLF & "extended: " & @extended)
	Next
EndFunc

;~ Set objRegistry=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
;~
;~ strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
;~ strValueName = "CD Burning"

;~ objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strBurnFolder

;~ Const $BurnQueueFolder = @AppDataDir & "\Microsoft\CD Burning"
;~ Const $BurnDrive = "E:\"
;~ Const $BurnWizardTitle = "CD Writing Wizard"
;~ Const $BurnVerb = "Write &these files to CD"

;~ $oApp = ObjCreate("Shell.Application")

;debug verbs...
;~ $verbs=$oApp.Namespace($BurnDrive).Self.Verbs
;~ For $verb in $verbs
;~  ConsoleWrite($verb.name & @crlf)
;~ next

;~ $oApp.Namespace($burndrive).Self.InvokeVerbEx($BurnVerb)
;~ WinWait($BurnWizardTitle)
;~ WinActivate($BurnWizardTitle)
;~ Send("A CD Title")
;~ Send("{ENTER}")
;~ WinWaitClose($BurnWizardTitle)
